#pragma once
#include<iostream>
#include<cstring>
#include<cerrno>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include"nocopy.hpp"
#include"Comm.hpp"
#include"Log.hpp"
#include"InetAddr.hpp"
#include"Dict.hpp"
#include<unistd.h>
#include<functional>
const static uint16_t defaultport=8888;
const static int defaultfd=-1;
const static int defaultsize = 1024;

using func_t=std::function<void(const std::string&,std::string&)>;
using namespace LogModule;

class UdpServer:public nocopy
{
    public:
    UdpServer(func_t func,uint16_t port=defaultport):_port(port),_socketfd(defaultfd),_func(func)
    {
    }
    void Init()
    {
        //创建socket
        _socketfd=socket(AF_INET,SOCK_DGRAM,0);
        if(_socketfd<0)
        {
            LOG(LogModule::LogLevel::ERROR)<<"socket error,"<<errno<<":"<<strerror(errno);
            exit(Socket_Err);
        }
        LOG(LogModule::LogLevel::INFO)<<"socket success,socketfd:"<<_socketfd;
        //绑定
        struct sockaddr_in local;
        bzero(&local,sizeof(local));
        local.sin_family=AF_INET;
        local.sin_port=htons(_port);//一定要本地转网络
        local.sin_addr.s_addr=INADDR_ANY;//任意一个ip都可以
        //local.sin_addr.s_addr=inet_addr(_ip.c_str());//设置为指定ip
        int n=::bind(_socketfd,(sockaddr*)&local,sizeof(local));
        if(n!=0)
        {
            LOG(LogModule::LogLevel::ERROR)<<"bind error,"<<errno<<":"<<strerror(errno);
            exit(Bind_Err);
        }
    }
    void start()
    {
        LOG(LogModule::LogLevel::INFO)<<"服务器开始运行";
        char buffer[defaultsize];
        while(1)
        {
            struct sockaddr_in peer;
            socklen_t len=sizeof(peer);
            ssize_t n=recvfrom(_socketfd,buffer,sizeof(buffer),0,(sockaddr*)&peer,&len);
            LOG(LogModule::LogLevel::INFO)<<"收到消息";
            if(n>0)
            {
                InetAddr addr(peer);
                buffer[n]=0;
                std::cout << "[" << addr.PrintDebug() << "]# " <<buffer << std::endl;
                std::string val;
                _func(buffer,val);
                sendto(_socketfd,val.c_str(),val.size(),0,(sockaddr*)&peer,len);
            }
        }
    }
    ~UdpServer(){}
    private:
    std::string _ip;
    uint16_t _port;
    int _socketfd;
    func_t _func;
};